using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Diagnostics;
using System.Text;
using System.Text.Json;

namespace CoreManager.Core.Middleware
{
    /// <summary>
    /// 请求日志中间件
    /// </summary>
    public class RequestLoggingMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger<RequestLoggingMiddleware> _logger;

        public RequestLoggingMiddleware(RequestDelegate next, ILogger<RequestLoggingMiddleware> logger)
        {
            _next = next;
            _logger = logger;
        }

        public async Task InvokeAsync(HttpContext context)
        {
            // 生成唯一的 TraceId：使用 GUID 的前16位，确保全局唯一
            var requestId = Guid.NewGuid().ToString("N")[..16];
            context.Items["RequestId"] = requestId;

            // 记录请求开始时间
            var stopwatch = Stopwatch.StartNew();

            // 记录请求信息
            await LogRequestAsync(context, requestId);

            // 保存原始响应流
            var originalResponseBody = context.Response.Body;

            try
            {
                // 创建内存流来捕获响应
                using var responseBody = new MemoryStream();
                context.Response.Body = responseBody;

                // 执行下一个中间件
                await _next(context);

                // 记录响应信息
                stopwatch.Stop();
                await LogResponseAsync(context, requestId, stopwatch.ElapsedMilliseconds);

                // 将响应写回原始流
                responseBody.Seek(0, SeekOrigin.Begin);
                await responseBody.CopyToAsync(originalResponseBody);
            }
            catch (Exception ex)
            {
                stopwatch.Stop();
                await LogErrorAsync(context, requestId, ex, stopwatch.ElapsedMilliseconds);
                throw;
            }
            finally
            {
                context.Response.Body = originalResponseBody;
            }
        }

        /// <summary>
        /// 记录请求信息
        /// </summary>
        private Task LogRequestAsync(HttpContext context, string requestId)
        {
            var request = context.Request;
            var path = request.Path.Value;
            var method = request.Method;
            var queryString = request.QueryString.HasValue ? request.QueryString.Value : "";
            var userId = GetCurrentUserId(context);
            var clientIp = GetClientIpAddress(context);

            // 优化的链路追踪格式
            if (!string.IsNullOrEmpty(userId))
            {
                _logger.LogInformation("[请求ID:{RequestId}] 开始处理 → {Method} {Path}{QueryString} | 用户ID:{UserId} | 客户端IP:{ClientIp}",
                    requestId, method, path, queryString, userId, clientIp);
            }
            else
            {
                _logger.LogInformation("[请求ID:{RequestId}] 开始处理 → {Method} {Path}{QueryString} | 客户端IP:{ClientIp}",
                    requestId, method, path, queryString, clientIp);
            }
            
            return Task.CompletedTask;
        }

        /// <summary>
        /// 记录响应信息
        /// </summary>
        private Task LogResponseAsync(HttpContext context, string requestId, long elapsedMilliseconds)
        {
            var response = context.Response;
            var statusCode = response.StatusCode;
            var request = context.Request;
            
            // 优化的响应日志格式
            var logLevel = statusCode >= 400 ? LogLevel.Warning : LogLevel.Information;
            _logger.Log(logLevel, 
                "[请求ID:{RequestId}] 处理完成 ← {Method} {Path} | 状态码:{StatusCode} | 耗时:{ElapsedMs}ms ",
               requestId, request.Method, request.Path.Value, statusCode, elapsedMilliseconds);
                
            return Task.CompletedTask;
        }

        /// <summary>
        /// 记录错误信息
        /// </summary>
        private Task LogErrorAsync(HttpContext context, string requestId, Exception exception, long elapsedMilliseconds)
        {
            var request = context.Request;
            var userId = GetCurrentUserId(context);
            
            // 优化的错误日志格式
            if (!string.IsNullOrEmpty(userId))
            {
                _logger.LogError(exception, 
                    "💥 [请求ID:{RequestId}] 处理异常 → {Method} {Path} | 用户ID:{UserId} | 耗时:{ElapsedMs}ms | 异常类型:{ExceptionType} | 错误信息:{Message}",
                    requestId, request.Method, request.Path.Value, userId, elapsedMilliseconds, 
                    exception.GetType().Name, exception.Message);
            }
            else
            {
                _logger.LogError(exception, 
                    "💥 [请求ID:{RequestId}] 处理异常 → {Method} {Path} | 耗时:{ElapsedMs}ms | 异常类型:{ExceptionType} | 错误信息:{Message}",
                    requestId, request.Method, request.Path.Value, elapsedMilliseconds, 
                    exception.GetType().Name, exception.Message);
            }
                
            return Task.CompletedTask;
        }

        /// <summary>
        /// 读取请求体
        /// </summary>
        private async Task<string?> ReadRequestBodyAsync(HttpRequest request)
        {
            try
            {
                request.EnableBuffering();
                request.Body.Seek(0, SeekOrigin.Begin);

                using var reader = new StreamReader(request.Body, Encoding.UTF8, leaveOpen: true);
                var body = await reader.ReadToEndAsync();
                request.Body.Seek(0, SeekOrigin.Begin);

                // 过滤敏感信息
                return FilterSensitiveData(body);
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 读取响应体
        /// </summary>
        private async Task<string?> ReadResponseBodyAsync(HttpContext context)
        {
            try
            {
                context.Response.Body.Seek(0, SeekOrigin.Begin);
                using var reader = new StreamReader(context.Response.Body, Encoding.UTF8, leaveOpen: true);
                var body = await reader.ReadToEndAsync();
                context.Response.Body.Seek(0, SeekOrigin.Begin);

                return body.Length > 1000 ? body[..1000] + "..." : body;
            }
            catch
            {
                return null;
            }
        }

        /// <summary>
        /// 获取请求头信息
        /// </summary>
        private static Dictionary<string, string> GetHeaders(IHeaderDictionary headers)
        {
            var result = new Dictionary<string, string>();
            var excludeHeaders = new[] { "Authorization", "Cookie", "X-API-Key" };

            foreach (var header in headers)
            {
                if (!excludeHeaders.Contains(header.Key, StringComparer.OrdinalIgnoreCase))
                {
                    result[header.Key] = header.Value.ToString();
                }
            }

            return result;
        }

        /// <summary>
        /// 获取客户端IP地址
        /// </summary>
        private static string GetClientIpAddress(HttpContext context)
        {
            var ipAddress = context.Request.Headers["X-Forwarded-For"].FirstOrDefault();
            if (string.IsNullOrEmpty(ipAddress))
            {
                ipAddress = context.Request.Headers["X-Real-IP"].FirstOrDefault();
            }
            if (string.IsNullOrEmpty(ipAddress))
            {
                ipAddress = context.Connection.RemoteIpAddress?.ToString();
            }

            return ipAddress ?? "Unknown";
        }

        /// <summary>
        /// 获取当前用户ID
        /// </summary>
        private static string? GetCurrentUserId(HttpContext context)
        {
            return context.User?.FindFirst("sub")?.Value ??
                   context.User?.FindFirst("userId")?.Value ??
                   context.User?.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier)?.Value;
        }

        /// <summary>
        /// 过滤敏感数据
        /// </summary>
        private static string FilterSensitiveData(string content)
        {
            if (string.IsNullOrEmpty(content))
                return content;

            try
            {
                // 尝试解析为JSON并过滤敏感字段
                using var document = JsonDocument.Parse(content);
                var sensitiveFields = new[] { "password", "token", "secret", "key", "credential" };

                var filteredJson = FilterJsonElement(document.RootElement, sensitiveFields);
                return JsonSerializer.Serialize(filteredJson);
            }
            catch
            {
                // 如果不是JSON，直接返回（可能需要其他过滤逻辑）
                return content.Length > 500 ? content[..500] + "..." : content;
            }
        }

        /// <summary>
        /// 过滤JSON元素中的敏感字段
        /// </summary>
        private static object FilterJsonElement(JsonElement element, string[] sensitiveFields)
        {
            switch (element.ValueKind)
            {
                case JsonValueKind.Object:
                    var obj = new Dictionary<string, object>();
                    foreach (var property in element.EnumerateObject())
                    {
                        if (sensitiveFields.Any(field => 
                            property.Name.Contains(field, StringComparison.OrdinalIgnoreCase)))
                        {
                            obj[property.Name] = "***";
                        }
                        else
                        {
                            obj[property.Name] = FilterJsonElement(property.Value, sensitiveFields);
                        }
                    }
                    return obj;

                case JsonValueKind.Array:
                    return element.EnumerateArray()
                        .Select(item => FilterJsonElement(item, sensitiveFields))
                        .ToArray();

                case JsonValueKind.String:
                    return element.GetString() ?? "";

                case JsonValueKind.Number:
                    return element.GetDecimal();

                case JsonValueKind.True:
                    return true;

                case JsonValueKind.False:
                    return false;

                case JsonValueKind.Null:
                    return string.Empty; // 修复：返回空字符串而不是 null，避免 null 引用警告

                default:
                    return element.ToString();
            }
        }

        /// <summary>
        /// 是否记录响应体
        /// </summary>
        private static bool IsLoggingResponseBody()
        {
            // 可以通过配置控制是否记录响应体
            return Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT") == "Development";
        }
    }
}